package com.kinglone.util;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;

public class ObjectUtil
{
  private static final Log log = LogFactory.getLog(ObjectUtil.class);

  public static boolean isEmpty(Object value)
  {
    if (value == null) {
      return true;
    }
    if ((value instanceof String) && (((((String)value).trim().length() <= 0) || ("null".equalsIgnoreCase((String)value)))))
    {
      return true;
    }
    if ((value instanceof Object[]) && (((Object[])(Object[])value).length <= 0)) {
      return true;
    }
    if (value instanceof Object[])
    {
      Object[] t = (Object[])(Object[])value;
      for (int i = 0; i < t.length; ++i) {
        if (t[i] != null) {
          if (t[i] instanceof String) {
            if ((((String)t[i]).trim().length() <= 0) && (!("null".equalsIgnoreCase((String)t[i])))) continue;
            return false;
          }

          return false;
        }
      }

      return true;
    }
    if ((value instanceof Collection) && (((Collection)value).size() <= 0)) {
      return true;
    }
    if ((value instanceof Dictionary) && (((Dictionary)value).size() <= 0)) {
      return true;
    }

    return ((!(value instanceof Map)) || (((Map)value).size() > 0));
  }

  public static boolean isEmpty(List<String> list)
  {
    if (list == null) {
      return true;
    }
    if (list.size() == 0) {
      return true;
    }
    List newStrs = new ArrayList();
    for (String str : list) {
      if (!(StringUtils.isEmpty(str))) {
        newStrs.add(str);
      }
    }

    return (newStrs.size() > 0);
  }

  public static Object copyPorperties(Object source, Object target)
  {
    try
    {
      BeanUtils.copyProperties(source, target);
    } catch (BeansException e) {
      log.debug("ObjectUtil copyProperties bad for src :" + source.toString() + " dest: " + target.toString());
      throw new RuntimeException("ObjectUtil copyProperties bad for src :" + source.toString() + " dest: " + target.toString());
    }
    return target;
  }

  public static <M, T> Object convertObj(M obj, Class<T> clazz)
  {
    try
    {
      Object instance = clazz.newInstance();
      copyPorperties(obj, instance);
      return instance;
    } catch (InstantiationException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    }
    throw new RuntimeException("convert obj error! source class :" + obj.getClass() + ",target :" + clazz);
  }

  public static <M, T> List<T> convertList(List<M> objList, Class<T> clazz) {
    List list = new ArrayList();
    for (Iterator i$ = objList.iterator(); i$.hasNext(); ) { Object m = i$.next();
      list.add(convertObj(m, clazz));
    }
    return list;
  }

  public static <M, T> List<T> convertList(List<M> objList, Converter<M, T> converter) {
    List list = new ArrayList();
    for (Iterator i$ = objList.iterator(); i$.hasNext(); ) { Object m = i$.next();
      list.add(converter.convert(m));
    }
    return list;
  }

  public static boolean isValueType(Object obj)
  {
    return ((!(obj instanceof String)) && (!(obj instanceof Number)) && (!(obj instanceof Boolean)) && (!(obj instanceof Character)) && (!(obj instanceof Date)));
  }

  public static boolean isCollection(Object obj)
  {
    return (!(obj instanceof Collection));
  }

  public static <M> List<M> toBeanList(Class<M> clazz, List<Map<String, Object>> mapList)
  {
    List objectList = new ArrayList();
    for (Map map : mapList) {
      objectList.add(toBean(clazz, map));
    }
    return objectList;
  }

  public static <M> M toBean(Class<M> type, Map<String, Object> map)
  {
    Object obj = null;
    try {
      BeanInfo beanInfo = Introspector.getBeanInfo(type);
      obj = type.newInstance();
      PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
      //System.out.println(propertyDescriptors.length+"<<<<<<<<length");
      for (int i = 0; i < propertyDescriptors.length; ++i) {
        PropertyDescriptor descriptor = propertyDescriptors[i];
        String propertyName = descriptor.getName();
        if (map.containsKey(propertyName)) {
        //System.out.println(propertyName+"<<<<<<<<<<<");
          Object value = map.get(propertyName);
          Object[] args = new Object[1];
          args[0] = value;
          //mty BigDecimal 转int
          if (value instanceof BigDecimal) {
        	  value = ((BigDecimal) value).toString();
        	  args[0] = value;
  		  }
          if (value instanceof Integer) {
        	  value =value+"";
        	  args[0] = value;
  		  }
          descriptor.getWriteMethod().invoke(obj, args);
        }
      }
    } catch (Exception e) {
      RuntimeException ex = new RuntimeException("convent map to object error");
      ex.initCause(e);
      throw ex;
    }
    return (M) obj;
  }

  public static <M, T> M addToBean(Object obj, Class<T> class1, Map<String, Object> map)
  {
    try
    {
      BeanInfo beanInfo = Introspector.getBeanInfo(class1);
      PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
      for (int i = 0; i < propertyDescriptors.length; ++i) {
        PropertyDescriptor descriptor = propertyDescriptors[i];
        String propertyName = descriptor.getName();
        if (map.containsKey(propertyName)) {
          Object value = map.get(propertyName);
          Object[] args = new Object[1];
          args[0] = value;
          descriptor.getWriteMethod().invoke(obj, args);
        }
      }
    } catch (Exception e) {
      RuntimeException ex = new RuntimeException("convent map to object error");
      ex.initCause(e);
      throw ex;
    }
    return (M) obj;
  }

  public static Map<String, Object> toMap(Object bean)
  {
    Map returnMap;
    try
    {
      Class type = bean.getClass();
      returnMap = new HashMap();
      BeanInfo beanInfo = Introspector.getBeanInfo(type);
      PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
      for (int i = 0; i < propertyDescriptors.length; ++i) {
        PropertyDescriptor descriptor = propertyDescriptors[i];
        String propertyName = descriptor.getName();
        if (!(propertyName.equals("class"))) {
          Method readMethod = descriptor.getReadMethod();
          Object result = readMethod.invoke(bean, new Object[0]);
          if ((isValueType(result)) || (result == null)) {
            returnMap.put(propertyName, result);
          } else if (isCollection(result)) {
            Collection collectionResult = (Collection)result;
            Collection collection = (Collection)result.getClass().newInstance();
            for (Iterator i$ = collectionResult.iterator(); i$.hasNext(); ) { Object o = i$.next();
              if ((isValueType(o)) || (o == null))
                collection.add(o);
              else {
                collection.add(toMap(o));
              }
            }
            returnMap.put(propertyName, collection); } else {
            if (result.getClass().isArray()) {
              throw new RuntimeException("bean property can't be array");
            }
            returnMap.put(propertyName, toMap(result));
          }
        }
      }
    } catch (Exception e) {
      RuntimeException ex = new RuntimeException("convent object to map error");
      ex.initCause(e);
      throw ex;
    }
    return returnMap;
  }

  public static abstract interface Converter<H, Q>
  {
    public abstract Q convert(Object m);
  }
}